package com.parsechina.hpush.broker.spi.persistence.h2;

import com.parsechina.hpush.broker.config.MqttConstants;
import com.parsechina.hpush.broker.internal.MessageGUID;
import com.parsechina.hpush.broker.spi.persistence.GuidIndex;
import org.h2.mvstore.MVStore;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

/**
 * @author linfeng
 * @since 2016/12/7
 */
public class H2GuidStore implements Serializable {

    private static final long serialVersionUID = 7490858164703597409L;
    private final ConcurrentMap<String, GuidIndex> m_retainedIndex;

    public H2GuidStore(MVStore mvStore) {
        m_retainedIndex = mvStore.openMap(MqttConstants.CACHE_RETAINED_INDEX_KEY);
    }

    public void initGuidIndexStore(ConcurrentMap<String, MessageGUID> retainedIndexStore) {

        GuidIndex guidTrie = m_retainedIndex.get("guid_tree");
        for (Map.Entry<String, MessageGUID> entry : retainedIndexStore.entrySet()) {
            guidTrie.insert(entry.getKey(), entry.getValue());
        }
    }

    public void putGuidIndex(String key, MessageGUID guid) {
        GuidIndex guidTrie = m_retainedIndex.get("guid_tree");
        if (guidTrie == null) {
            guidTrie = new GuidIndex();
            m_retainedIndex.put("guid_tree", guidTrie);
        }
        guidTrie.insert(key, guid);
    }

    public void removeGuidIndex(String key) {
        GuidIndex guidTrie = m_retainedIndex.get("guid_tree");
        if (guidTrie == null) {
            guidTrie = new GuidIndex();
            m_retainedIndex.put("guid_tree", guidTrie);
        }
        guidTrie.deleteWord(key);
    }

    public List<MessageGUID> searchPrefixGuidIndex(String key) {

        GuidIndex guidTrie = m_retainedIndex.get("guid_tree");
        if (guidTrie == null) {
            guidTrie = new GuidIndex();
            m_retainedIndex.put("guid_tree", guidTrie);
        }
        GuidIndex.GuidNode guidNode = guidTrie.searchPrefix(key);
        List<MessageGUID> results = new ArrayList<>(guidNode.count);
        if (guidNode.nodeMap.isEmpty()) {
            results.add(guidNode.guid);
        } else {
            guidTrie.listAllGuidOfNode(guidNode, results);
        }
        return results;
    }

    public MessageGUID searchOneGuidIndex(String key) {
        GuidIndex guidTrie = m_retainedIndex.get("guid_tree");
        if (guidTrie == null) {
            guidTrie = new GuidIndex();
            m_retainedIndex.put("guid_tree", guidTrie);
        }
        return guidTrie.searchOne(key);
    }

    public List<MessageGUID> complexSearchGuidIndex(String key) {


        GuidIndex guidTrie = m_retainedIndex.get("guid_tree");
        if (guidTrie == null) {
            guidTrie = new GuidIndex();
            m_retainedIndex.put("guid_tree", guidTrie);
        }

        List<GuidIndex.GuidNode> guidNodes = guidTrie.complexSearch(key);
        List<MessageGUID> results = new ArrayList<>();
        if (guidNodes.isEmpty()) {
            return results;
        }
        for (GuidIndex.GuidNode guidNode : guidNodes) {
            guidTrie.listAllGuidOfNode(guidNode, results);
        }
        return results;
    }
}
